using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml;
using System.Xml.Linq;
using GuidanceExplorer.Controls;
using GuidanceExplorer.Model;
using GuidanceExplorer.Schemas;
using GuidanceExplorer.Services;
using GuidanceExplorerAddIn.Properties;



namespace GuidanceExplorerAddIn.Services
{
    public class AddinModelStorageService : ModelStorageService, IAddinModelStorageService
    {
		//private readonly string ConfigurationFileName = "GuidanceExplorer.config";

		/// <summary>
		/// The solution guidance instance
		/// </summary>
        //public Guidance Guidance { get { return _addinGuidance; } private set { _addinGuidance = value; _guidance = _addinGuidance; } }

       // private Guidance _addinGuidance;
		/// <summary>
		/// List filled whenever a checklist is loaded. Used for updating them later with the checklists file.
		/// </summary>
		private List<Checklist> loadedChecklists = new List<Checklist>();

		/// <summary>
		/// Fields that shouldn't be considered CustomFields of a GuidanceItem
		/// </summary>
		private readonly List<String> nonCustomFields = new List<string>(new String[]
		{ 
			SchemaHelper.GuidanceItem.Id, 
			SchemaHelper.GuidanceItem.Type, 
			SchemaHelper.GuidanceItem.Title, 
			SchemaHelper.GuidanceItem.CSSFile, 
			SchemaHelper.GuidanceItem.Date,
			SchemaHelper.ChecklistItem.IsChecked
		});



		/// <summary>
		/// Default constructor
		/// </summary>
		public AddinModelStorageService()
		{
            //Guidance = Guidance.New();
            System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
            if (configuration.AppSettings.Settings.AllKeys.Contains<string>("LibraryFolder"))
            {
                libraryFolder = configuration.AppSettings.Settings["LibraryFolder"].Value;
				// For checking if the folder exist.

				string libraryFolderPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), libraryFolder));
                DirectoryInfo libraryDir = new DirectoryInfo(libraryFolderPath);
 
                if (! libraryDir.Exists)
				{
                    string configFile = System.Reflection.Assembly.GetExecutingAssembly().Location + ".config";
					throw new Exception(String.Format(Resources.InvalidLibrary,libraryDir.FullName,configFile));
				}

            }
            if (configuration.AppSettings.Settings.AllKeys.Contains<string>("TemplateFolder"))
            {
                templateFolder = configuration.AppSettings.Settings["TemplateFolder"].Value;
				// For checking if the folder exist.
				string templateFolderPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), templateFolder));
				if (!Directory.Exists(templateFolderPath))
				{
					throw new Exception(Resources.InvalidTemplate);
				}
            }
            if (configuration.AppSettings.Settings.AllKeys.Contains<string>("SolutionGuidanceFolder"))
            {
                guidanceFolderName = configuration.AppSettings.Settings["SolutionGuidanceFolder"].Value;
            }
		}


		#region Load

        //public new Guidance Guidance
        //{
        //    get { return Guidance; }
        //}

        //public new Guidance LoadGuidance(string currentDirectory, ClientFlavour clientFlavour)
        //{
        //    //System.Configuration.ConfigurationSettings.AppSettings[""]
        //    //Create the guidance type filename
        //    string guidanceTypeFileName = Path.GetFullPath(Path.Combine(currentDirectory, "GuidanceTypes.xml"));

        //    //Load all guidance type information
        //    LoadGuidanceTypes(new FileInfo(guidanceTypeFileName));

        //    // Creates the guidance support.
        //   // _guidance = Guidance.New();
        //    //_guidance.ClientFlavour = clientFlavour;
        //    Guidance.ClientFlavour = clientFlavour;

        //    string libraryBaseFolder = Path.GetFullPath(Path.Combine(currentDirectory, LibraryFolder));
        //    if (Directory.Exists(libraryBaseFolder))
        //    {
        //        string librariesColumns = Path.Combine(libraryBaseFolder, LibrariesColumnsConfiguration);

        //        if (File.Exists(librariesColumns))
        //        {
        //            using (XmlReader reader = XmlTextReader.Create(librariesColumns))
        //            {
        //                Guidance.Columns = ConvertXmlReaderToColumns(reader);
        //            }
        //        }

        //        foreach (string file in Directory.GetFiles(libraryBaseFolder, "*.xml"))
        //        {
        //            FileInfo fileInfo = new FileInfo(file);
        //            if (TypeOfLibraryFile(fileInfo) == TypeOfLibrary.Library)
        //            {
        //                try
        //                {
        //                    Library library = ConvertFileInfoToLibrary(fileInfo);
        //                    Guidance.Libraries.Add(library.Name, library);
        //                }
        //                catch (IOException ioEx)
        //                {
        //                    Forms.MessageBox.Show(ioEx.Message, Messages.ERROR, Forms.MessageBoxButtons.OK, Forms.MessageBoxIcon.Error);
        //                }
        //                catch (Exception)//If the library load fails, ignore that library
        //                { }
        //            }
        //            else if (TypeOfLibraryFile(fileInfo) == TypeOfLibrary.UserViews)
        //            {
        //                UserViews userViews = ConvertFileInfoToUserViews(fileInfo);
        //                Guidance.UserViews = userViews;
        //            }
        //            else if (TypeOfLibraryFile(fileInfo) == TypeOfLibrary.GlobalViews)
        //            {
        //                //GlobalViews globalViews = ConvertFileInfoToGlobalViews(fileInfo);
        //                //Guidance.GlobalViews = globalViews;
        //            }

        //        }
        //    }

        //    return Guidance;
        //}


		/// <summary>
		/// Loads the guidances for the specified solution
		/// </summary>
		/// <param name="solution"></param>
        public void LoadSolutionGuidance(string solutionName,string solutionFullName)
        {
            // Create the SolutionGuidance
            if (_guidance == null)
            {
                _guidance = Guidance.New();
            }
            Guidance.SolutionViews = SolutionViews.New();
            Guidance.SolutionViews.SolutionName = solutionName;
            Guidance.SolutionViews.SolutionFolder = new DirectoryInfo(Path.GetDirectoryName(solutionFullName));
            Guidance.SolutionViews.SolutionGuidanceFolder = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(solutionFullName), guidanceFolderName));

            // If the guidance items folder doesn't exists, create it
            if (!Guidance.SolutionViews.SolutionGuidanceFolder.Exists)
            {
                Guidance.SolutionViews.SolutionGuidanceFolder.Create();
            }

            // If the guidances file exists, open it. Else, create a blank solution with the default items
            string guidanceFilePath = Path.Combine(Guidance.SolutionViews.SolutionFolder.FullName, Resources.GuidanceXmlFileName);
            //SolutionGuidanceProp.SolutionFolder.SourceFileInfo = guidanceFile;
            if (File.Exists(guidanceFilePath))
            {
                // Load the solution guidances structure
                loadedChecklists.Clear();
                this.LoadSolutionGuidance(guidanceFilePath);

                // If there's a checklists values and notes file, load it
                string checklistsFilePath = Path.Combine(Guidance.SolutionViews.SolutionFolder.FullName, Resources.ChecklistXmlFileName);
                if (File.Exists(checklistsFilePath))
                {
                    this.LoadSolutionChecklists(checklistsFilePath);
                }
            }
            else
            {
                // Create default cheklist
                Checklist checklist = Checklist.New();
                checklist.Caption = "Checklist";
                checklist.Container = Guidance.SolutionViews;
                Guidance.SolutionViews.Checklists.Add(checklist.Caption, checklist);
            }
        }
        
        public void ImportSolution(String guidanceFilePath)
        {
            String fromExportPath = Path.GetDirectoryName(guidanceFilePath);
            UpdateFilePathNewItems(guidanceFilePath);
            LoadSolutionGuidance(guidanceFilePath);

            String checkListPath = Path.Combine(fromExportPath, Resources.ChecklistXmlFileName);
            if (File.Exists(checkListPath))
            {
                this.LoadSolutionChecklists(checkListPath);
            }
            DirectoryInfo di =new DirectoryInfo(Path.Combine(fromExportPath, guidanceFolderName));
            if (di.Exists)
            {
                foreach (FileInfo fi in di.GetFiles())
                {
                    fi.CopyTo(Path.Combine(Guidance.SolutionViews.SolutionGuidanceFolder.FullName, fi.Name), true);
                }
            }       
        }
        public void ImportItemSolutionToFolder(String guidanceFilePath, Folder folder)
        {
            String fromExportPath = Path.GetDirectoryName(guidanceFilePath);
            String guidanceFolderPath = Path.Combine(fromExportPath, guidanceFolderName);
            UpdateFilePathNewItems(guidanceFilePath);
            
            
            LoadSolutionGuidanceToFolder(guidanceFilePath,folder);

            String checkListPath = Path.Combine(fromExportPath, Resources.ChecklistXmlFileName);
            if (File.Exists(checkListPath))
            {
                this.LoadSolutionChecklists(checkListPath);
            }
            DirectoryInfo di = new DirectoryInfo(guidanceFolderPath);
            if (di.Exists)
            {
                foreach (FileInfo fi in di.GetFiles())
                {
                    fi.CopyTo(Path.Combine(Guidance.SolutionViews.SolutionGuidanceFolder.FullName, fi.Name), true);
                }
            }
        }

        private void UpdateFilePathNewItems(String guidanceFilePath)
        {

            XElement guidanceXml = XElement.Load(guidanceFilePath);
            XElement solutionXml = guidanceXml.Element(SchemaHelper.Solution.Element);

            ReplaceFilePath(this.Guidance.SolutionViews.SolutionGuidanceFolder.FullName, solutionXml);
            guidanceXml.Save(guidanceFilePath);
        }

        private static void ReplaceFilePath(String guidanceFilePath, XElement solutionXml)
        {

            foreach (XElement elemXml in solutionXml.Elements())
            {
                if (elemXml.Element(SchemaHelper.View.Items) != null)
                {
                    foreach (XElement subItem in elemXml.Element(SchemaHelper.View.Items).Elements(SchemaHelper.GuidanceItem.Element))
                    {
                        String newFilePath = Path.Combine(guidanceFilePath, Path.GetFileName(subItem.Attribute(SchemaHelper.GuidanceItem.FilePath).Value));
                        subItem.SetAttributeValue(SchemaHelper.GuidanceItem.FilePath, newFilePath);
                    }
                }
                if (elemXml.Element(SchemaHelper.Checklist.Items) != null)
                {
                    foreach (XElement subItem in elemXml.Element(SchemaHelper.Checklist.Items).Elements(SchemaHelper.ChecklistItem.Element))
                    {
                        String newFilePath = Path.Combine(guidanceFilePath, Path.GetFileName(subItem.Attribute(SchemaHelper.GuidanceItem.FilePath).Value));
                        subItem.SetAttributeValue(SchemaHelper.GuidanceItem.FilePath, newFilePath);
                    }
                
                }
                ReplaceFilePath(guidanceFilePath, elemXml);
            }
        }

		private void LoadSolutionGuidance(string guidanceFilePath)
		{
            XElement solutionXml = InitializeSolutionGuidance(guidanceFilePath);
			// Load all the root folders
			foreach (XElement folderXml in solutionXml.Elements(SchemaHelper.Folder.Element))
			{
				LoadSolutionRootFolder(folderXml);
			}

			// Load all the root views
			foreach (XElement viewXml in solutionXml.Elements(SchemaHelper.View.Element))
			{
				LoadSolutionRootView(viewXml);
			}
			
			// Load all the root checklists
			foreach (XElement checklistXml in solutionXml.Elements(SchemaHelper.Checklist.Element))
			{
				LoadSolutionRootChecklist(checklistXml);
			}
		}

        private  XElement InitializeSolutionGuidance(string guidanceFilePath)
        {
            // Load guidance file
            XElement guidanceXml = XElement.Load(guidanceFilePath);
            XElement solutionXml = guidanceXml.Element(SchemaHelper.Solution.Element);

            // Load solution info
            if (Guidance.SolutionViews.SolutionName == String.Empty)
            {
                Guidance.SolutionViews.SolutionName = solutionXml.Attribute(SchemaHelper.Solution.Name).Value;
            }
            return solutionXml;
        }
        private void LoadSolutionGuidanceToFolder(string guidanceFilePath, Folder folder)
        {
            XElement solutionXml = InitializeSolutionGuidance(guidanceFilePath);

            AddAllToFolder(solutionXml,folder);
        }

		private void LoadSolutionRootFolder(XElement folderXml)
		{
			// Create the new folder and add it to the parent collection
            Folder newFolder;
            if (!Guidance.SolutionViews.Folders.ContainsKey(folderXml.Attribute(SchemaHelper.Folder.Caption).Value))
            {
                newFolder = Folder.New();
                newFolder.Container = Guidance.SolutionViews;
                newFolder.Caption = folderXml.Attribute(SchemaHelper.Folder.Caption).Value;
                Guidance.SolutionViews.Folders.Add(newFolder.Caption, newFolder);
            }
            else
            {
                newFolder = Guidance.SolutionViews.Folders[folderXml.Attribute(SchemaHelper.Folder.Caption).Value];
            }

            AddAllToFolder(folderXml, newFolder);
		}

        private void AddAllToFolder(XElement folderXml, Folder newFolder)
        {
            // Add to the new folder all sub folders
            foreach (XElement subFolder in folderXml.Elements(SchemaHelper.Folder.Element))
            {
                LoadSolutionFolder(subFolder, newFolder);
            }

            // Add to the new folder all sub views
            foreach (XElement subView in folderXml.Elements(SchemaHelper.View.Element))
            {
                LoadSolutionView(subView, newFolder);
            }

            // Add to the new folder all sub checklists
            foreach (XElement subChecklist in folderXml.Elements(SchemaHelper.Checklist.Element))
            {
                LoadSolutionChecklist(subChecklist, newFolder);
            }
        }

		private void LoadSolutionRootView(XElement viewXml)
		{
			// Create the new view and add it to the parent collection
            View newView;
            if (Guidance.SolutionViews.Views.ContainsKey(viewXml.Attribute(SchemaHelper.View.Caption).Value))
            {
                newView = Guidance.SolutionViews.Views[viewXml.Attribute(SchemaHelper.View.Caption).Value];
            }
            else
            {
                newView = View.New();
                newView.Caption = viewXml.Attribute(SchemaHelper.View.Caption).Value;
             
                Guidance.SolutionViews.Views.Add(newView.Caption, newView);
            }
            newView.Id = viewXml.Attribute(SchemaHelper.View.Id).Value;
            newView.LastUpdate = DateTime.Parse(viewXml.Attribute(SchemaHelper.View.CreationDate).Value);
            newView.Description = viewXml.Attribute(SchemaHelper.View.Description).Value;
            newView.Author = viewXml.Attribute(SchemaHelper.View.Author).Value;
            newView.Description = viewXml.Attribute(SchemaHelper.View.Description).Value;
            newView.RootView = viewXml.Attribute(SchemaHelper.View.RootView).Value == "true";
            newView.Container = Guidance.SolutionViews;

			// Add to the new view all sub items
			foreach (XElement subItem in viewXml.Element(SchemaHelper.View.Items).Elements(SchemaHelper.GuidanceItem.Element))
			{
				LoadSolutionViewItem(subItem, newView);
			}
		}

		private void LoadSolutionRootChecklist(XElement checklistXml)
		{
			// Create the new checklist and add it to the parent collection
            Checklist newChecklist;
            if (Guidance.SolutionViews.Checklists.ContainsKey(checklistXml.Attribute(SchemaHelper.Checklist.Caption).Value))
            {
                newChecklist = Guidance.SolutionViews.Checklists[checklistXml.Attribute(SchemaHelper.Checklist.Caption).Value];
                if (!loadedChecklists.Contains(newChecklist))
                {
                    loadedChecklists.Add(newChecklist);
                }
            }
            else
            {
                newChecklist = Checklist.New();
                newChecklist.Caption = checklistXml.Attribute(SchemaHelper.Checklist.Caption).Value;

                Guidance.SolutionViews.Checklists.Add(newChecklist.Caption, newChecklist);
                loadedChecklists.Add(newChecklist);
            }
            newChecklist.Id = checklistXml.Attribute(SchemaHelper.Checklist.Id).Value;
            newChecklist.LastUpdate = DateTime.Parse(checklistXml.Attribute(SchemaHelper.Checklist.CreationDate).Value);
            newChecklist.Description = checklistXml.Attribute(SchemaHelper.Checklist.Description).Value;
            newChecklist.Author = checklistXml.Attribute(SchemaHelper.Checklist.Author).Value;
            newChecklist.Description = checklistXml.Attribute(SchemaHelper.Checklist.Description).Value;
            newChecklist.RootView = checklistXml.Attribute(SchemaHelper.Checklist.RootView).Value == "true";
            newChecklist.Container = Guidance.SolutionViews;

                
			// Add to the new checklist all sub items
			foreach (XElement subItem in checklistXml.Element(SchemaHelper.Checklist.Items).Elements(SchemaHelper.ChecklistItem.Element))
			{
				LoadSolutionChecklistItem(subItem, newChecklist);
			}
		}

		private void LoadSolutionFolder(XElement folderXml, Folder parent)
		{
			// Create the new folder and add it to the parent collection
			Folder newFolder ;
            if (parent.Folders.ContainsKey(folderXml.Attribute(SchemaHelper.Folder.Caption).Value))
            {
                newFolder = parent.Folders[folderXml.Attribute(SchemaHelper.Folder.Caption).Value];
            }
            else
            {
                newFolder = Folder.New();
                newFolder.Caption = folderXml.Attribute(SchemaHelper.Folder.Caption).Value;
                newFolder.ParentFolder = parent;
                parent.Folders.Add(newFolder.Caption, newFolder);
            }
			// Add to the new folder all sub folders
			foreach (XElement subFolder in folderXml.Elements(SchemaHelper.Folder.Element))
			{
				LoadSolutionFolder(subFolder, newFolder);
			}

			// Add to the new folder all sub views
			foreach (XElement subView in folderXml.Elements(SchemaHelper.View.Element))
			{
				LoadSolutionView(subView, newFolder);
			}

			// Add to the new folder all sub checklists
			foreach (XElement subChecklist in folderXml.Elements(SchemaHelper.Checklist.Element))
			{
				LoadSolutionChecklist(subChecklist, newFolder);
			}
		}

		private void LoadSolutionView(XElement viewXml, Folder parent)
		{
			// Create the new view and add it to the parent collection
            View newView;
            
            if (parent.Views.ContainsKey(viewXml.Attribute(SchemaHelper.View.Caption).Value))
            {
                newView = parent.Views[viewXml.Attribute(SchemaHelper.View.Caption).Value];
            }
            else
            {
                newView = View.New();
                newView.Caption = viewXml.Attribute(SchemaHelper.View.Caption).Value;
                parent.Views.Add(newView.Caption, newView);

            }
            newView.Id = viewXml.Attribute(SchemaHelper.View.Id).Value;
            newView.LastUpdate = DateTime.Parse(viewXml.Attribute(SchemaHelper.View.CreationDate).Value);
            newView.Description = viewXml.Attribute(SchemaHelper.View.Description).Value;
            newView.Author = viewXml.Attribute(SchemaHelper.View.Author).Value;
            newView.Description = viewXml.Attribute(SchemaHelper.View.Description).Value;
            newView.RootView = viewXml.Attribute(SchemaHelper.View.RootView).Value == "true";
            newView.ParentFolder = parent;
          
          
			// Add to the new view all sub items
			foreach (XElement subItem in viewXml.Element(SchemaHelper.View.Items).Elements(SchemaHelper.GuidanceItem.Element))
			{
				LoadSolutionViewItem(subItem, newView);
			}
		}

		private void LoadSolutionChecklist(XElement checklistXml, Folder parent)
		{
			// Create the new checklist and add it to the parent collection
            Checklist newChecklist;
            if (parent.Checklists.ContainsKey(checklistXml.Attribute(SchemaHelper.Checklist.Caption).Value))
            {
                newChecklist = parent.Checklists[checklistXml.Attribute(SchemaHelper.Checklist.Caption).Value];
                if (!loadedChecklists.Contains(newChecklist))
                {
                    loadedChecklists.Add(newChecklist);
                }
            }
            else
            {
                newChecklist = Checklist.New();
                newChecklist.Caption = checklistXml.Attribute(SchemaHelper.Checklist.Caption).Value;
                
                parent.Checklists.Add(newChecklist.Caption, newChecklist);
                loadedChecklists.Add(newChecklist);
            }
            newChecklist.Id = checklistXml.Attribute(SchemaHelper.Checklist.Id).Value;
            newChecklist.LastUpdate = DateTime.Parse(checklistXml.Attribute(SchemaHelper.Checklist.CreationDate).Value);
            newChecklist.Description = checklistXml.Attribute(SchemaHelper.Checklist.Description).Value;
            newChecklist.Author = checklistXml.Attribute(SchemaHelper.Checklist.Author).Value;
            newChecklist.Description = checklistXml.Attribute(SchemaHelper.Checklist.Description).Value;
            newChecklist.RootView = checklistXml.Attribute(SchemaHelper.Checklist.RootView).Value == "true";
            newChecklist.ParentFolder = parent;

			
			// Add to the new checklist all sub items
			foreach (XElement subItem in checklistXml.Element(SchemaHelper.Checklist.Items).Elements(SchemaHelper.ChecklistItem.Element))
			{
				LoadSolutionChecklistItem(subItem, newChecklist);
			}
		}

		private void LoadSolutionViewItem(XElement itemXml, GuidanceExplorer.Model.View parent)
		{
            if (parent.Items.ContainsKey(itemXml.Attribute(SchemaHelper.GuidanceItem.Id).Value))
            {
                parent.Items.Remove(itemXml.Attribute(SchemaHelper.GuidanceItem.Id).Value);
            }
			GuidanceItemFileReference newItem = GuidanceItemFileReference.New();
			newItem.Id = itemXml.Attribute(SchemaHelper.GuidanceItem.Id).Value;
			newItem.GuidanceType = GuidanceType.New(itemXml.Attribute(SchemaHelper.GuidanceItem.Type).Value);
			newItem.Title = itemXml.Attribute(SchemaHelper.GuidanceItem.Title).Value;
			newItem.CSSFile = itemXml.Attribute(SchemaHelper.GuidanceItem.CSSFile).Value;
			newItem.DateTime = DateTime.Parse(itemXml.Attribute(SchemaHelper.GuidanceItem.Date).Value);
			newItem.FileName = itemXml.Attribute(SchemaHelper.GuidanceItem.FilePath).Value;
			//newItem.Source = itemXml.Attribute(SchemaHelper.GuidanceItem.Source).Value;

			// Load item custom data
			foreach (XAttribute attribute in itemXml.Attributes())
			{
				if (!nonCustomFields.Contains(attribute.Name.ToString()) &&
                     ! newItem.CustomData.ContainsKey(attribute.Name.ToString()))
                {
					newItem.CustomData.Add(attribute.Name.ToString(), attribute.Value);
				}
			}
			parent.Items.Add(newItem.Id, newItem);
		}

		private void LoadSolutionChecklistItem(XElement itemXml, Checklist parent)
		{
            if (parent.Items.ContainsKey(itemXml.Attribute(SchemaHelper.GuidanceItem.Id).Value))
            {
                parent.Items.Remove(itemXml.Attribute(SchemaHelper.GuidanceItem.Id).Value);
            }
			GuidanceItemFileReference newItem = GuidanceItemFileReference.New();
			newItem.Id = itemXml.Attribute(SchemaHelper.GuidanceItem.Id).Value;
			newItem.GuidanceType = GuidanceType.New(itemXml.Attribute(SchemaHelper.GuidanceItem.Type).Value);
			newItem.Title = itemXml.Attribute(SchemaHelper.GuidanceItem.Title).Value;
			newItem.CSSFile = itemXml.Attribute(SchemaHelper.GuidanceItem.CSSFile).Value;
			newItem.DateTime = DateTime.Parse(itemXml.Attribute(SchemaHelper.GuidanceItem.Date).Value);
			newItem.FileName = itemXml.Attribute(SchemaHelper.GuidanceItem.FilePath).Value;
			//newItem.Source = itemXml.Attribute(SchemaHelper.ChecklistItem.Source).Value;

			// Load item custom data
			foreach (XAttribute attribute in itemXml.Attributes())
			{
				if (!nonCustomFields.Contains(attribute.Name.ToString()) &&
                  ! newItem.CustomData.ContainsKey(attribute.Name.ToString()))
                {
					newItem.CustomData.Add(attribute.Name.ToString(), attribute.Value);
				}
			}

			parent.Items.Add(newItem.Id, newItem);
		}


		private void LoadSolutionChecklists(string checklistsFilePath)
		{
		    // Load checklists xml
		    XElement checklistsXml = XElement.Load(checklistsFilePath);

		    // For each checklist item in the file, update the checklist at the model
		    foreach (XElement itemXml in checklistsXml.Element(SchemaHelper.Solution.Element).Elements(SchemaHelper.ChecklistItem.Element))
		    {
		        string id = itemXml.Attribute(SchemaHelper.ChecklistItem.Id).Value;
		        bool check = itemXml.Attribute(SchemaHelper.ChecklistItem.Checked).Value == "true" ? true : false; 
		        string notes = itemXml.Element(SchemaHelper.ChecklistItem.Notes).Value;

		        // Find the checklist parent of the current item and update it
				Checklist checklist = FindChecklistOfGuidanceItem(id);
		        checklist.SetCheck(id, check);
		        checklist.SetItemNotes(id, notes);
		    }
		}

		private Checklist FindChecklistOfGuidanceItem(string guidanceItemId)
		{ 
			// For each loaded checklist, check if ti has the rquired guidance item
			foreach (Checklist checklist in loadedChecklists)
			{
				if(checklist.Items.Values.Select(g => g.Id).Contains(guidanceItemId))
				{
					return checklist;
				}
			}

			return null;
		}

		#endregion


        #region Save and Export

		string GetNameOfModelItem(IModelItem node)
		{
			return ((System.Windows.Forms.TreeNode)node).Text.Trim() + ".xml";
		}

        public void ExportSolutionModelItem(String savePath, IModelItem node)
        {

            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;

            // Open the guidances file and write the solution structure
			string guidancesFile = Path.Combine(savePath, GetNameOfModelItem(node));
            using (FileStream fileStream = new FileStream(guidancesFile, FileMode.Create))
            using (XmlWriter writer = XmlTextWriter.Create(fileStream, settings))
            {
                // Write headers
                writer.WriteStartDocument();
                writer.WriteStartElement(SchemaHelper.GuidanceExplorer.Element/*, SchemaHelper.Namespace*/);		// TODO: Create the schema and validate generated xmls
                writer.WriteStartElement(SchemaHelper.Solution.Element);
                writer.WriteAttributeString(SchemaHelper.Solution.Name, Guidance.SolutionViews.SolutionName);

                if (node is FolderNode)
                {
                    RenderFolderToXmlWriter(((FolderNode)node).ModelInstance as Folder, writer);
                }
                else if (node is ChecklistNode)
                {
                    RenderChecklistStructureToXmlWriter(((ChecklistNode)node).ModelInstance as Checklist, writer);
                }
                else if (node is ViewNode)
                {
                    RenderViewToXmlWriter(((ViewNode)node).ModelInstance as View, writer);
                }
                // Write footers
                writer.WriteEndElement();
                writer.WriteEndElement();
                writer.WriteEndDocument();
            }
            if (!Directory.Exists(Path.Combine(savePath, guidanceFolderName)))
            {
                Directory.CreateDirectory(Path.Combine(savePath, guidanceFolderName));
            }
            CopyItems(savePath, node );
            
        }
        private void CopyItems(String savePath, IModelItem modelItem)
        {
            if (modelItem is GuidanceItem)
            {
                GuidanceItemFileReference gifr = (GuidanceItemFileReference)((GuidanceItem)modelItem);
                FileInfo fi = new FileInfo(gifr.FullFileName);
                fi.CopyTo(Path.Combine(Path.Combine(savePath, guidanceFolderName), fi.Name), true);
            }else if(modelItem is ChecklistNode)
            {
                Checklist checkList = (Checklist)((ChecklistNode) modelItem).ModelInstance;
                foreach (GuidanceItem item in checkList.Items)
                {
                    CopyItems(savePath, item);
                }
            }else if(modelItem is ViewNode){
                View view = (View)((ViewNode)modelItem).ModelInstance;
                foreach (GuidanceItem item in view.Items)
                {
                    CopyItems(savePath, item);
                }
            }
            else if (modelItem is FolderNode)
            {
                Folder folder = (Folder) ((FolderNode)modelItem).ModelInstance;
              
                foreach (System.Windows.Forms.TreeNode item in ((FolderNode)modelItem).Nodes)
                {
                    CopyItems(savePath, item as IModelItem);
                }
            }
            
        }
        public void ExportSolution(String savePath)
        {
            SaveSolutionGuidance(savePath);

            if (!Directory.Exists(Path.Combine(savePath, guidanceFolderName)))
            {
                Directory.CreateDirectory(Path.Combine(savePath, guidanceFolderName));
            }
            foreach (FileInfo fi in  new DirectoryInfo(Guidance.SolutionViews.SolutionGuidanceFolder.FullName).GetFiles())
            {
                fi.CopyTo(Path.Combine(Path.Combine(savePath, guidanceFolderName),fi.Name),true);
            }
        }

        
        public void SaveSolutionGuidance()
        {
			//Delete from the filesystem the UI deleted items.
			DeleteItemsIfNotReferenced(Guidance.SolutionViews.ItemsToDelete); 

			SaveSolutionGuidance(Guidance.SolutionViews.SolutionFolder.FullName);
        }

		private void DeleteItemsIfNotReferenced(List<GuidanceItemFileReference> list)
		{
			foreach (GuidanceItemFileReference gifr in list)
			{
				if (!HasLink(gifr))
				{
					if (File.Exists(gifr.FullFileName))
					{
						File.Delete(gifr.FullFileName);
					}
				}
			}
		}

        /// <summary>
		/// Saves the guidances for the current solution
		/// </summary>
        public void SaveSolutionGuidance(String savePath)
        {
			// XmlWriter settings
			XmlWriterSettings settings = new XmlWriterSettings();
			settings.Indent = true;

			// Open the guidances file and write the solution structure
            string guidancesFile = Path.Combine(savePath, Resources.GuidanceXmlFileName);
			using (FileStream fileStream = new FileStream(guidancesFile, FileMode.Create))
            using (XmlWriter writer = XmlTextWriter.Create(fileStream, settings))
			{
				// Write headers
				writer.WriteStartDocument();
				writer.WriteStartElement(SchemaHelper.GuidanceExplorer.Element/*, SchemaHelper.Namespace*/);		// TODO: Create the schema and validate generated xmls
				writer.WriteStartElement(SchemaHelper.Solution.Element);
				writer.WriteAttributeString(SchemaHelper.Solution.Name, Guidance.SolutionViews.SolutionName);

				// Save the folders
				foreach (Folder folder in this.Guidance.SolutionViews.Folders.Values)
				{
					RenderFolderToXmlWriter(folder, writer);
				}

				// Save the views
				foreach (View view in this.Guidance.SolutionViews.Views.Values)
				{
					RenderViewToXmlWriter(view, writer);
				}

				// Save the checklists structure
				foreach (Checklist checklist in this.Guidance.SolutionViews.Checklists.Values)
				{
					RenderChecklistStructureToXmlWriter(checklist, writer);
				}
				
				// Write footers
				writer.WriteEndElement();
				writer.WriteEndElement();
				writer.WriteEndDocument();
			}


			// Open the checklists file and write the checklists values
            string checklistsFile = Path.Combine(savePath, Resources.ChecklistXmlFileName);
            using (FileStream fileStream = new FileStream(checklistsFile, FileMode.Create))
            using (XmlWriter writer = XmlTextWriter.Create(fileStream, settings))
			{
				// Write headers
				writer.WriteStartDocument();
				writer.WriteStartElement(SchemaHelper.GuidanceExplorer.Element);
				writer.WriteStartElement(SchemaHelper.Solution.Element);

				// Save the checklist items inside the solution folders
				foreach (Folder folder in this.Guidance.SolutionViews.Folders.Values)
				{
					RenderChecklistItemsValuesAtFolderToXmlWriter(folder, writer);
				}

				// Save the checklists items at solution checklists
				foreach (Checklist checklist in Guidance.SolutionViews.Checklists.Values)
				{
					RenderChecklistItemsValuesToXmlWriter(checklist, writer);
				}

				// Write footers
				writer.WriteEndElement();
				writer.WriteEndElement();
				writer.WriteEndDocument();
			}
        }

		/// <summary>
		/// Render an instance of a View into an XmlWriter.
		/// </summary>
		/// <param name="view">The view to render.</param>
		/// <param name="writer">The xmlwriter to render to.</param>
		protected void RenderViewToXmlWriter(GuidanceExplorer.Model.View view, XmlWriter writer)
		{
			writer.WriteStartElement(SchemaHelper.View.Element);
			writer.WriteAttributeString(SchemaHelper.View.Id, view.Id);
			writer.WriteAttributeString(SchemaHelper.View.Caption, view.Caption);
			writer.WriteAttributeString(SchemaHelper.View.CreationDate, XmlConvert.ToString(view.LastUpdate, XmlDateTimeSerializationMode.Local));
			writer.WriteAttributeString(SchemaHelper.View.Description, view.Description);
			writer.WriteAttributeString(SchemaHelper.View.Author, view.Author);
			writer.WriteAttributeString(SchemaHelper.View.RootView, XmlConvert.ToString(view.RootView));

			//Render the columns.
			//RenderColumnCollectionToXmlWriter(view.Columns, writer);

			//Render view items.
			RenderViewGuidanceItemCollectionToXmlWriter(view.Items, writer);

			writer.WriteEndElement(); //SchemaHelper.View.Element
		}


		/// <summary>
		/// Render the item collection for a view into an XmlWriter.
		/// </summary>
		/// <param name="guidanceItemCollection">The GuidanceItemCollection to render.</param>
		/// <param name="writer">The xmlwriter to render to.</param>
		private void RenderViewGuidanceItemCollectionToXmlWriter(GuidanceItemCollection guidanceItemCollection, XmlWriter writer)
		{
			writer.WriteStartElement(SchemaHelper.Items.Element);

			// Write all the item Ids.
			foreach (GuidanceItem item in guidanceItemCollection.Values)
			{
				writer.WriteStartElement(SchemaHelper.GuidanceItem.Element);

				//GuidanceItemFileReference fileRef = item as GuidanceItemFileReference;
				//if (fileRef != null)
				//{
				//    writer.WriteAttributeString(SchemaHelper.GuidanceItem.FilePath, fileRef.FileName);
				//}
				writer.WriteAttributeString(SchemaHelper.GuidanceItem.Id, item.Id);
				writer.WriteAttributeString(SchemaHelper.GuidanceItem.Type, item.GuidanceType.Name);
				writer.WriteAttributeString(SchemaHelper.GuidanceItem.Title, item.Title);
				writer.WriteAttributeString(SchemaHelper.GuidanceItem.CSSFile, item.CSSFile);
				writer.WriteAttributeString(SchemaHelper.GuidanceItem.Date, XmlConvert.ToString(item.DateTime, XmlDateTimeSerializationMode.RoundtripKind));

				// Write the custom attributes.
				foreach (string fieldKey in item.CustomData.Keys)
				{
					if(!nonCustomFields.Contains(fieldKey))
                    {
						writer.WriteAttributeString(fieldKey, item.CustomData[fieldKey]);
					}
				}

				writer.WriteEndElement();
			}
			writer.WriteEndElement();
		}

		/// <summary>
		/// Render the columns collection into an XmlWriter.
		/// </summary>
		/// <param name="columns">The columns collection instance to render.</param>
		/// <param name="writer">The XmlWriter to render to.</param>
		//protected new void RenderColumnCollectionToXmlWriter(ColumnCollection columns, XmlWriter writer)
		//{
		//    writer.WriteStartElement(SchemaHelper.Columns.Element);

		//    foreach (Column column in columns.Values)
		//    {
		//        writer.WriteStartElement(SchemaHelper.Column.Element);
		//        writer.WriteAttributeString(SchemaHelper.Column.Source, column.Source);
		//        writer.WriteAttributeString(SchemaHelper.Column.Caption, column.Caption);
		//        writer.WriteAttributeString(SchemaHelper.Column.Sort, column.Sort.ToString());
		//        writer.WriteAttributeString(SchemaHelper.Column.Visible, XmlConvert.ToString(column.Visible));
		//        writer.WriteAttributeString(SchemaHelper.Column.Width, XmlConvert.ToString(column.Width));
		//        writer.WriteAttributeString(SchemaHelper.Column.Position, XmlConvert.ToString(column.Position));

		//        if (!string.IsNullOrEmpty(column.AutoFilter))
		//        {
		//            writer.WriteAttributeString(SchemaHelper.Column.Filter, column.AutoFilter);
		//        }

		//        writer.WriteEndElement(); //SchemaHelper.Column.Element
		//    }

		//    writer.WriteEndElement(); //SchemaHelper.Columns.Element
		//}


		/// <summary>
		/// Renders the contents of a folder (only views or other folders) in the model to an XmlWriter instance.
		/// </summary>
		/// <param name="folder">The folder to render.</param>
		/// <param name="writer">The xmlwriter to render to.</param>
		protected void RenderFolderToXmlWriter(Folder folder, XmlWriter writer)
		{
			writer.WriteStartElement(SchemaHelper.Folder.Element);
			writer.WriteAttributeString(SchemaHelper.Folder.Caption, folder.Caption);

			//Render the columns.
			//RenderColumnCollectionToXmlWriter(folder.Columns, writer);

			//Render child folders.
			foreach (Folder childFolder in folder.Folders.Values)
			{
				RenderFolderToXmlWriter(childFolder, writer);
			}

			// Render child views.
			foreach (GuidanceExplorer.Model.View childView in folder.Views.Values)
			{
				//SearchView searchView = childView as SearchView;
				//if (searchView != null)
				//{
				//    RenderSearchViewToXmlWriter(searchView, writer);
				//}
				//else
				{
					RenderViewToXmlWriter(childView, writer);
				}
			}

			// Render child checklists
			foreach (Checklist checklist in folder.Checklists.Values)
			{
				RenderChecklistStructureToXmlWriter(checklist, writer);
			}

			writer.WriteEndElement(); //SchemaHelper.Folder.Element
		}

		/// <summary>
		/// Renders the contents of a folder (only checklists or other folders) in the model to an XmlWriter instance.
		/// </summary>
		/// <param name="folder">The folder to render.</param>
		/// <param name="writer">The xmlwriter to render to.</param>
		protected void RenderChecklistItemsValuesAtFolderToXmlWriter(Folder folder, XmlWriter writer)
		{
			// Render child folders.
			foreach (Folder childFolder in folder.Folders.Values)
			{
				RenderChecklistItemsValuesAtFolderToXmlWriter(childFolder, writer);
			}

			// Render child checklists.
			foreach (Checklist checklist in folder.Checklists.Values)
			{
				RenderChecklistItemsValuesToXmlWriter(checklist, writer);
			}
		}


		/// <summary>
		/// Render an instance of a Checklist into an XmlWriter.
		/// </summary>
		/// <param name="view">The view to render.</param>
		/// <param name="writer">The xmlwriter to render to.</param>
		private void RenderChecklistStructureToXmlWriter(Checklist checklist, XmlWriter writer)
		{
			// Render the checklist attributes
			writer.WriteStartElement(SchemaHelper.Checklist.Element);
			writer.WriteAttributeString(SchemaHelper.Checklist.Id, checklist.Id);
			writer.WriteAttributeString(SchemaHelper.Checklist.Caption, checklist.Caption);
			writer.WriteAttributeString(SchemaHelper.Checklist.CreationDate, XmlConvert.ToString(checklist.LastUpdate, XmlDateTimeSerializationMode.Local));
			writer.WriteAttributeString(SchemaHelper.Checklist.Description, checklist.Description);
			writer.WriteAttributeString(SchemaHelper.Checklist.Author, checklist.Author);
			writer.WriteAttributeString(SchemaHelper.Checklist.RootView, XmlConvert.ToString(checklist.RootView));

			// Render the columns.
			//RenderColumnCollectionToXmlWriter(checklist.Columns, writer);

			// Render the checklist items
			//writer.WriteStartElement(SchemaHelper.Checklist.Element);
			RenderChecklistItemsStructureToXmlWriter(checklist, writer);

			writer.WriteEndElement(); //SchemaHelper.View.Element
		}

		/// <summary>
		/// Render all items in a Checklist into an XmlWriter.
		/// </summary>
		/// <param name="view">The view to render.</param>
		/// <param name="writer">The xmlwriter to render to.</param>
		private void RenderChecklistItemsStructureToXmlWriter(Checklist checklist, XmlWriter writer)
		{
			writer.WriteStartElement(SchemaHelper.Checklist.Items);

			// Write all the checklist items Ids
			foreach (GuidanceItem item in checklist.Items)
			{
				writer.WriteStartElement(SchemaHelper.ChecklistItem.Element);
				writer.WriteAttributeString(SchemaHelper.ChecklistItem.Id, item.Id);
				writer.WriteAttributeString(SchemaHelper.ChecklistItem.Type, item.GuidanceType.Name);
				writer.WriteAttributeString(SchemaHelper.ChecklistItem.Title, item.Title);
				writer.WriteAttributeString(SchemaHelper.ChecklistItem.CSSFile, item.CSSFile);
				writer.WriteAttributeString(SchemaHelper.ChecklistItem.Date, XmlConvert.ToString(item.DateTime, XmlDateTimeSerializationMode.RoundtripKind));

				// Write the custom attributes.
				foreach (string fieldKey in item.CustomData.Keys)
				{
					if (!nonCustomFields.Contains(fieldKey))
					{
						writer.WriteAttributeString(fieldKey, item.CustomData[fieldKey]);
					}
				}

				writer.WriteEndElement();
			}

			writer.WriteEndElement();
		}

		/// <summary>
		/// Render all items in a Checklist into an XmlWriter.
		/// </summary>
		/// <param name="view">The view to render.</param>
		/// <param name="writer">The xmlwriter to render to.</param>
		private void RenderChecklistItemsValuesToXmlWriter(Checklist checklist, XmlWriter writer)
		{
			// Write all the checklist items Ids and values
			foreach (GuidanceItem item in checklist.Items)
			{
				writer.WriteStartElement(SchemaHelper.ChecklistItem.Element);
				
				writer.WriteAttributeString(SchemaHelper.ChecklistItem.Checked, checklist.IsChecked(item.Id) ? "true" : "false");
				writer.WriteAttributeString(SchemaHelper.ChecklistItem.Id, item.Id);
				writer.WriteStartElement(SchemaHelper.ChecklistItem.Notes);
				writer.WriteCData(checklist.GetItemNotes(item.Id));
				writer.WriteEndElement();

				writer.WriteEndElement();
			}
		}

		#endregion
        

		#region Public Methods

        public GuidanceItemFileReference CopyItemByValueToSolution(GuidanceItemFileReference guidanceItem)
        {
            return CopyItemByValueToSolution(guidanceItem, Guidance.SolutionViews.SolutionGuidanceFolder.FullName);
        }
		public GuidanceItemFileReference CopyItemByValueToSolution(GuidanceItemFileReference guidanceItem, String savePath)
        {
			GuidanceItemFileReference newItem = guidanceItem.Clone();
			newItem.Id = Guid.NewGuid().ToString();
			newItem.FileName = newItem.Id + ".xml";
			newItem.CustomData[SchemaHelper.GuidanceItem.FilePath] = newItem.FileName;
			newItem.Library = null; //TODO: set solution as item container
            newItem.CustomData[SchemaHelper.GuidanceItem.Source] = Guidance.SolutionViews.SolutionName;
            newItem.DateTime = DateTime.Now;

            string oldItemFile = ((GuidanceItemFileReference)guidanceItem).FileName;
            string newItemPath = Path.Combine(savePath, newItem.FileName);
            newItem.FileName = newItemPath;
            if (! Path.IsPathRooted(oldItemFile))
            {
                //string newDirName = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), libraryFolder);
                oldItemFile = Path.Combine(LibraryFolder, oldItemFile);
            }
			// Load item file and make needed changes
			XElement xml = XElement.Load(oldItemFile);
			xml.Attribute(SchemaHelper.GuidanceItem.Id).Value = newItem.Id;
            xml.Attribute(SchemaHelper.GuidanceItem.FilePath).Value = newItem.FileName;
            xml.Attribute(SchemaHelper.GuidanceItem.Source).Value = Guidance.SolutionViews.SolutionName;
			xml.Save(newItemPath);

            return newItem;

		}

		#endregion
	}
}
